#include "matrix.h"

#include <stdlib.h>
#include <QStringList>
#include <QRegExp>
#include <QDebug>
// #include <QMessageBox>


Matrix::Matrix()
{
    matrix = NULL;
    rows = 0;
    cols = 0;
}


Matrix::~Matrix()
{
    if (matrix != NULL) {
        free(matrix);
        // delete[] matrix;
        qDebug() << " free ";
        matrix = NULL;
    }
}
void Matrix::destory(){
    if (matrix != NULL) {
        free(matrix);
        // delete[] matrix;
        qDebug() << " free ";
        matrix = NULL;
    }
}

void Matrix::create2(QString str){
    // list1: [ "a", "", "b", "c" ]
    // str += "\r\nHAHA";
    QString result="";
    QString line="";
    int rows = 0;
    int cols = 0;
    int curCols = 0;
    for (int i = 0; i < str.size(); ++i) {
        const QChar	c = str.at(i);
        if (c == QChar('\n')){
            result += QString("line: %1 , %2 \n").arg(rows).arg(line);
            rows++;
            if (curCols> cols) {
                cols = curCols;
            }
            line="";
            curCols = 0;
        } else if (c == QChar(' ') || c == QChar('\t')){
            // col need skip
            line += ',';
        } else if ( c.isDigit() || c == QChar('.')  || c == QChar('-') ) {
            // isNumber isDigit
            // qDebug() << "Found character in range [0-9]";
            // bool ok;
            // double d;
            // d=QString("1234.56e-02").toDouble(&ok);
            QString data = "";
            while( ( str.at(i).isDigit() || str.at(i) == QChar('.')  || str.at(i) == QChar('-') ) && i < str.size()){
                line += str.at(i);
                i++;
            }
            i--;
            curCols++;
        } else {
            qDebug() << "skip invalid char " << c;
        }
    }
    if (line.size() > 0) {
        result += QString("line: %1 , %2 \n").arg(rows).arg(line);
        rows++;
        if (curCols> cols) {
            cols = curCols;
        }
    } else {
        // rows--;
    }
    result += QString("\nTotal row: %1 , cols %2 ").arg(rows).arg(cols);
}
void Matrix::create(QString str)
{
    // QStringList list1 = str.split(QLatin1Char('\n'));
    QStringList list = str.split( QRegExp("[\r\n]"),QString::SkipEmptyParts);
    rows = list.size();
    // calculate the columns
    int curCols = 0;
    for (int i = 0; i < rows; ++i) {
        QString l = list.at(i);
        QStringList ll = l.split(QRegExp("\\s+"), Qt::SkipEmptyParts);
        curCols = ll.size();
        if (curCols> cols) {
            cols = curCols;
        }
    }
    // fill the matrix
    // rows = 2;
    // cols = 2;
    qDebug() << " malloc by string ";

    int size = rows*cols +1;
    matrix = (int*)malloc(sizeof(int) * size);
    // matrix = new int[size];

    int offset = 0;
    for (int i = 0; i < rows; ++i) {
        QString l = list.at(i);
        QStringList ll = l.split(QRegExp("\\s+"), Qt::SkipEmptyParts);
        //      cout << list.at(i).toLocal8Bit().constData() << Qt::endl;
        curCols = ll.size();
        for (int j = 0; j < curCols; ++j) {
            bool ok;
            // double d = ll.at(j).toDouble(&ok) ;
            int d = ll.at(j).toInt(&ok) ;
            // qDebug() << "  " << ll.at(j) << "  " << d << "   " << ok;
            matrix[offset] = d;
            offset++;
        }
        for (int j = curCols; j < cols; ++j) {
            matrix[offset] = 0;
            offset++;
        }
        // qDebug() << " ----------------- ";
    }

}

QString Matrix::dump(){
    QString s = QString("matrix: rows %1 , cols %2 \n-------------\n").arg(rows).arg(cols);
    int i,j;
    int offset;
    for (i = 0; i < rows; i++) {
      offset = i * cols;
      for (j = 0; j < cols; j++) {
            // printf("%d ", matrix[offset+j]);
          s += QString("%1 ").arg(matrix[offset+j]);
        }
        // printf("\n");
      s += "\n";
    }
    return s;
}


/**
 * Matrix A, row * column, element (i,j)
 * A(i,j)m*s  B(i,j)s*n
 * C = A*B = C(i,j)m*n  c(i,j) = sum(a(i,k)*b(k,j))
 *
 * m1,m2 is input matrix, m1 is x*y, m2 is y*z
 * r is the result matrx, is x*z
 *
 * refer: https://zhuanlan.zhihu.com/p/108085571
 */
Matrix* Matrix::multiply(Matrix& b){
    if (this->cols != b.rows) {
        // QMessageBox::about(this, "BAD " , "cols != rows");
        qDebug() << " ----------------- ";
        return NULL;
    }
    Matrix* c = new Matrix();
    c->rows = this->rows;
    c->cols = b.cols;
    qDebug() << " malloc c ";
    int size = c->rows*c->cols +1;
    // c->matrix = new int[size];
    c->matrix = (int*)malloc(sizeof(int) * size );
    int *m1p;
    int *m2p;
    int offsetR=0;
    int k;
    int row;
    int column;

    for ( row = 0; row < this->rows; row ++ ) {
        for ( column = 0; column < b.cols; column ++ ) {
        m1p = this->matrix + row * this->cols;
        m2p = b.matrix + column;
        c->matrix[offsetR] = 0;

        for ( k = 0; k < this->cols; k ++) {
            c->matrix[offsetR] += *m1p * *m2p;
            m1p += 1;
            m2p += b.cols;
        }
        offsetR++;
    // printf("---- M1*M2: %d, %d  %d \n", row, column, offsetR);
    // print(r, x,z);
        }
    }
    QString msg = c->dump();
    qDebug() << " ----------------- " << msg;
    // QMessageBox::about(this, "C " , msg );
    return c;
}

Matrix* Matrix::plus(Matrix& b){
    // qDebug() << QString(" -- %1 ---%2 %3 %4 ------------ ").arg(this->rows).arg(*m1p).arg(*m2p).arg(*rp);
    if (this->rows != b.rows || this->cols != b.cols) {
        // QMessageBox::about(this, "BAD " , "not same rows and cols");
        qDebug() << " ----------------- ";
        return NULL;
    }
    Matrix* c = new Matrix();
    c->rows = this->rows;
    c->cols = b.cols;
    qDebug() << " malloc c ";
    int size = c->rows * c->cols;
    // c->matrix = new int[size];
    c->matrix = (int*)malloc(sizeof(int) * size );
    // int *m1p;
    // int *m2p;
    // int offsetR=0;
    // int k;
    // int row;
    // int column;
// void matrix_plus (int *m1, int *m2, int *r, int x, int y ) {
    int *m1p;
    int *m2p;
    int *rp;
    int num;

    m1p = this->matrix;
    m2p = b.matrix;
    rp = c->matrix;


    for ( num = size; num > 0 ; num-- ) {
        *rp = *m1p + *m2p;
        qDebug() << QString(" -- %1 ---%2 %3 %4 ------------ ").arg(num).arg(*m1p).arg(*m2p).arg(*rp);
        rp++;
        m1p++;
        m2p++;
    }
    return c;
}
